home *** CD-ROM | disk | FTP | other *** search
-
- The Keycode Story
- =================
-
- or
-
- How to get more from your keyboard
- ==================================
-
- The PRM isn't very forthcoming about the way the keyboard is handled, so
- this file attempts to explain how things work, as well as giving the
- rationale for the way the KeyChange module works. The information was
- gleaned from VERY careful reading of the "Character Input" section of the
- PRM (among others), plus quite a lot of experimentation, but I don't
- guarantee that it's all exactly right. The main problems are that the PRM
- fails to distinguish between things done by the keyboard handler and by
- OS_ReadC (which are logically quite distinct), and fails to make very clear
- what codes are inserted into the keyboard buffer in different conditions.
- All page references are to the 1st edition (issue 1) PRM.
-
- To begin with, it's very important to understand the difference between
- five concepts:
-
- 1) Function keys - these are the physical red (or grey) keys along the top
- of the keyboard, the Print and Insert keys (F0 and F13 in disguise), and
- the cursor, Page Up/Down, copy and tab keys (if you set them up
- appropriately).
-
- 2) Function key strings (or expansions) - these are the strings assigned to
- the variables Key$0 to Key$15 with *Key or whatever, that get used when
- you hit a function key outside the desktop. These aren't usually used in
- the desktop environment.
-
- 3) Function key (buffer) codes - these are the codes inserted into the
- keyboard buffer when you hit a function key. They are in the range
- &80-&FF.
-
- 4) Top-bit-set characters - these are also in the range &80-&FF, but are
- just treated as normal characters. They are distinguished from function
- key codes in the buffer by being preceded by a zero (ASCII NUL), as
- described below.
-
- 5) Codes returned by OSReadC - these are what your program will normally
- see. Normal and top-bit-set characters are just returned as they stand,
- but function key codes can be treated in different ways - discarded,
- translated into a function key string, returned as a NUL followed by the
- code (allowing them to be distinguished from top-bit-set characters),
- or returned as a top-bit-set character (although not necessarily the one
- with the same code!).
-
- Confused? You will be ...
-
- Things start with a keyboard interrupt whenever you press or release a
- key. This can be trapped as event 11 (see p. 122), which gives you a
- hardware keycode which is different for every key on the keyboard, and tells
- you if the key went down or up. It also gives you a keyboard driver ID, but
- no information is given about it, so this isn't very helpful. This means
- that the KeyChange module may not work with non-UK keyboards, although there
- is a gap for an extra code between left-Shift and "Z", so maybe all is OK.
- (Do Acorn make any other keyboards, anyway?) It may also help to know that
- the row and column legends on the table are the wrong way around, i.e. the
- numbers along the top are the high byte and the ones down the side are the
- low byte.
-
- Unfortunately, the event is purely informational, so you can't alter the
- keycode at this stage. The BBC micro had a Key Vector which did let you
- change the code, but this seems to be the only vector that didn't make it
- from the beeb. The PRM does say that you can replace the keyboard handler
- completely, but "[i]t is outside the scope of this manual to discuss this
- procedure in depth" (p. 468). How can anything be outside the scope of the
- PRM?
-
- Anyway, the keyboard handler translates the hardware code into a buffer
- code, except for shifting and locking keys, and escape and break if enabled.
- Escape is a story in itself; see the table on p. 472. The shift and lock
- keys just change an internal flag, which (sometimes) modifies the code
- produced by the other keys. You can change the code produced by the tab key
- with OS_Byte 219, and (to a very limited extent) those produced by the
- keypad with OS_Bytes 238 and 254. Apart from this, the code that enters the
- keyboard buffer is that given in the table on p. 520, EXCEPT that ASCII NUL
- (Ctrl-@) is entered as two NUL characters in a row. Incidentally, note that
- the Page Up/Down keys are effectively just shifted versions of the up/down
- cursor keys.
-
- Furthermore, if you have the InternationalKeyboard module enabled, it
- allows you to use the Alt keys as shifting keys with various normal keys to
- get top-bit-set characters, and to type ASCII codes on the keypad. These
- codes are entered into the keyboard buffer as TWO characters, a NUL followed
- by the top-bit-set character. Alt with keys that don't give a top-bit-set
- character don't give a buffer code at all. If you *Unplug or *RMKill the
- InternationalKeyboard module, Alt keys make no difference to the keycode
- generated by other keys, and top-bit-set characters can't be typed (as far
- as I know). [By this I mean that you can't put them in the buffer; as
- described below, OS_ReadC can return function key codes as top-bit-set
- characters. You could also put them in by hand with OS_Byte 138.] The fact
- that these characters are entered with a preceding NUL means that you can
- distinguish top-bit-set characters from function key codes, a vitally
- important fact!
-
- Once the code is emitted by the keyboard handler you can start
- manipulating it, by grabbing either the buffer insert or buffer remove
- vector. KeyChange uses buffer insert, as it needs to know about shifting
- keys; codes can be removed from the buffer a long time after they're
- inserted, so you might have taken your finger off the shift key by then! The
- two vectors are otherwise more-or-less equivalent, as nothing happens to the
- codes in between. The main thing to remember is that any code preceded by a
- NUL has to be passed unchanged, assuming you only want to mess around with
- function key codes. Incidentally, if you pull characters out of the buffer
- directly with OS_Byte 145 you'll see the nulls, but OS_ReadC and everything
- that calls it deals with translated codes.
-
- The buffer insertion code is called in IRQ mode, and another thing that
- the PRM fails to make clear is whether you can call the OS_Bytes which check
- the keyboard status (e.g. OS_Byte 121 or 202) in this case. The description
- says "interrupt status is not altered", which looks OK, but also says
- "re-entrancy not defined". What exactly is the difference between
- "undefined" re-entrancy and non-re-entrancy? I suspect that it is OK to call
- them, but just to be safe KeyChange traps the key up/down event referred to
- earlier, and keeps its own record of the state of keys in which it's
- interested. [The more I use the PRM, the more I feel that Acorn have skimped
- on defining the entry and exit conditions for SWIs etc.; at first sight it
- all looks clear, but the closer you look the less certain it all gets. As a
- good example, I believe it to be true that the data block used in Wimp SWIs
- remains unchanged except where values are explicitly returned, but I'm
- pretty sure it does't say so anywhere. End of whinge.]
-
- Most programs that use the keyboard get characters with OS_ReadC, or with
- something like OS_ReadLine that calls it. This passes all normal codes
- (below &80) and all top-bit-set characters without interpretation, except
- for removing any leading NUL. This includes all control codes;
- interpretation of Return, Ctrl-U and Delete is done by OS_ReadLine, and
- other codes normally only have an effect once they're echoed to OS_WriteC.
- (In the Wimp environment all codes are just passed to tasks to deal with as
- they wish).
-
- The cursor and copy keys give buffer codes as shown in the table on page
- 520. Depending on the mode selected by OS_Byte 4 they either trigger cursor
- editing, return top-bit-set characters (not the same ones as their buffer
- codes), or get treated as standard function key codes. These are interpreted
- according to the setting of OS_Bytes 221-228; they can be discarded,
- expanded, returned as a NUL followed by the code (which is the opposite of
- how they're stored in the buffer!), or returned as top-bit-set characters.
- Note that any codes above &7F in function key strings are returned as
- top-bit-set characters, and not interpreted as function key codes.
-
- The Wimp adds yet another twist to all this. It programs the cursor and
- copy keys to be treated as normal function keys, and the tab key to give
- code &8A (modified appropriately by Shift and Ctrl), which you can't
- otherwise get from the keyboard. Note that this isn't the same as F10 due to
- the strange way the codes are set out; F0-F9 are &80-&89, but F10-F13 are
- &CA-&CD (F13 is the Insert key). Following this interpretation, F14 and F15
- don't really exist. However, this doesn't mean that you can't access the
- function key strings for F14 and F15, as only the low nibble of the code is
- used to determine the string used. Outside the desktop, if you program the
- cursor keys to act as function keys with OS_Byte 4 you can get at the F14
- and F15 strings with the up and down cursor keys, just as you can get the
- F11 and F12 strings with the left and right cursor keys. (Simple, isn't it?)
-
- Anyway, the Wimp also uses OS_Bytes 221-228 to make all function key codes
- be returned preceded by a NUL. It then internally translates this to the 32
- bit value passed on the Key_Pressed wimp event, which adds &100 to the code
- for function keys. Thus the upshot is that wimp tasks see all codes between
- &20 and &FF as normal characters, with control codes between &00 and &1F as
- usual, and function key values between &180 and &18F, giving you a possible
- 160 codes to use as hot keys etc. The only fly in the ointment is that,
- although the wimp will happily translate any function key code, you can't
- actually type 48 of them. I'm typing this with Deskedit, which uses all but
- 6 of the available function key combinations (i.e. the ones you get with the
- red keys), most control codes, and some extras of its own that it must get
- by reading the keyboard directly. Thus if you want to use a hot-key
- application, you're pretty restricted in your choices. Enter KeyChange!
-
- An initial look at the keyboard shows that the options are fairly limited,
- as most of the keys are in use already; the only realistic candidates for
- additional uses are the Alt keys, the right-hand Ctrl key, Num Lock and
- perhaps Scroll Lock (which doesn't appear to do anything in the desktop). To
- get extra "function key" codes you really need a shifting key, although I
- suppose you could use Scroll Lock if you ignored the LED and didn't use it
- outside the desktop.
-
- The most obvious candidates are the Alt keys, as they probably aren't used
- much by most people; unfortunately, with the InternationalKeyboard module
- active they don't generate buffer codes at all with most keys, and if you
- *Unplug it you can't type top-bit set characters. Thus I decided to use Alt
- with a fallback to the right-hand Ctrl for people who want to type
- top-bit-set characters.
-
- The next step was to see which codes you can already get, and look for the
- best way of generating the rest. Looking at the tables on p. 520 and p. 1198
- shows that under the Wimp, with the tab, cursor and copy keys producing
- codes rather than effects, you can get all of the codes between &80 and &BF
- inclusive, plus &CA-&CD, &DA-&DD, &EA-&ED and &FA-&FD. Thus you need to
- generate four extra codes from function keys F0-F9, plus the non-existent
- F14 and F15. You can do this with one shifting key, as long as you don't
- mind having to hit four keys to get some of the codes! With two shifting
- keys you could get all codes with no more than three keys pressed, but this
- clashed with my desire to have an option to use the right Ctrl, and would
- also mean that you'd have to remember which codes went with which Alt key.
- Anyway, you get up to another 36 codes with a maximum of three keys pressed
- at once, so this should be fairly acceptable.
-
- A further problem was that the mythical F14 and F15 are shifted versions
- of the up and down cursor keys. Ctrl-cursor is a standard way of moving
- around text in !Edit etc., and I always use the right-hand Ctrl key for this
- as it's obviously convenient; however, I almost never use the right-hand
- Ctrl with the function keys (possibly related to being right-handed). Thus I
- decided that when using the right-hand Ctrl key only F0-F9 would change, so
- you lose 8 possible codes but don't make so many mistakes! The Alt key still
- gives the full range, as you wouldn't normally use Alt with the cursor keys
- (note that this makes Alt-left cursor duplicate F12).
-
- Having sorted all this out, I turned to the keypad. My original idea was
- to use the Num Lock-off state for function keys, as there can't be many
- people who use this mode (or even know it exists). However, a look at the
- table on p. 528 shows that a) the codes it generates are bizarre, and b) the
- "5" key doesn't generate a code at all, which makes things difficult for a
- program that works by trapping buffer insertions. I therefore settled on the
- rather odd method of using the Num Lock-on state, and toggling between
- different modes with Num Lock plus Ctrl or Shift. I really don't think Acorn
- thought about what they were doing with the keypad! About the only useful
- thing is that there are 16 keys, plus Num Lock and Enter, which is just
- right.
-
- Since you don't normally use Ctrl with the keypad it's OK to use it as a
- shifting key for all of the function keys. Thus in either Alt or right-Ctrl
- mode you can generate all 128 codes, although pressing Ctrl-Ctrl-Shift-#
- does require you to have more than the standard number of hands!
-
- So, there's the rationale; I think I've done about the best that's
- possible, but things would have been a lot better if Acorn had provided
- extra shifting keys (as on the Mac, for example), if it had standardised the
- use of hot keys more, and if the keypad were easier to control.
-